package com.buer.train.common.aspect;


import com.buer.train.business.domain.UserDO;
import com.buer.train.common.annotation.Auth;
import com.buer.train.common.constant.Constant;
import com.buer.train.common.eumn.RequestType;
import com.buer.train.common.eumn.ResultEnum;
import com.buer.train.common.handle.BaseException;
import com.buer.train.common.holder.LoginUser;
import com.buer.train.common.holder.LoginUserHolder;
import com.buer.train.common.holder.UserCacheHolder;
import com.buer.train.common.utils.Aes;
import com.buer.train.common.utils.CheckEmptyUtil;
import com.buer.train.common.utils.RedisUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.EnumUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;


/**
 *
 * @ProjectName:
 * @Package:        com.buer.train.common.aspect
 * @ClassName:      AuthAspect
 * @Description:    java类作用描述
 * @Author:         lds
 * @CreateDate:     2021/1/14 17:23
 * @UpdateUser:     更新者
 * @UpdateDate:     2021/1/14 17:23
 * @UpdateRemark:   更新内容
 * @Version:        1.0
 */
@Aspect
@Component
public class
AuthAspect {
    private static final Logger logger = LoggerFactory.getLogger(AuthAspect.class);

    @Autowired
    private HttpServletRequest request;



    @Pointcut("@annotation(com.buer.train.common.annotation.Auth)")
    public void AuthPointCut() {
    }

    @Before("AuthPointCut()")
    public void around(JoinPoint point){
        String appTypeStr = request.getHeader(Constant.REQUEST_TYPE);
        logger.info("用户请求头：{}",appTypeStr);
        String tokenStr = request.getHeader(Constant.REQUEST_TOKEN);
        logger.info("用户Token：{}",tokenStr);
        String requestServletPath=request.getServletPath();
        logger.info("请求地址为：{}",requestServletPath);
        //step1 验证请求是否合法
        checkLegality(appTypeStr,tokenStr);
        //step2 验证redis中token是否存在
        UserCacheHolder cacheHolder=checkTokenAndGetUser(appTypeStr,tokenStr);
        //step3 穿插业务判断
        checkBusinessParams(cacheHolder.getUserDo());
        //step4 判断请求的资源合法
        checkAuthority(cacheHolder.getLoginUser(),point,requestServletPath,appTypeStr);
        //step5 存入本地线程池
        LoginUserHolder.setLoginUserHolder(cacheHolder.getLoginUser());

    }

    private void checkAuthority(LoginUser loginUser,JoinPoint point,String requestServletPath,String appTypeStr) {
        if(appTypeStr.equals(RequestType.HT.toString())) {
            MethodSignature ms = (MethodSignature) point.getSignature();
            Method method = ms.getMethod();
            Auth myAuth = method.getAnnotation(Auth.class);
            String value = myAuth.value();
            if (CheckEmptyUtil.isNotEmpty(value)) {
                List<String> resources = loginUser.getResources();
                if (!resources.contains(value)) {
                    logger.error("该用户请求的地址为：{}，没有用户权限", requestServletPath);
                    throw new BaseException(ResultEnum.NOT_AUTH);
                }
            }
        }
    }

    private void checkLegality(String appTypeStr, String tokenStr) {
        if (StringUtils.isBlank(appTypeStr) || StringUtils.isBlank(tokenStr)) {
            logger.error("requestType或token不能为空，请求不合法");
            throw new BaseException(ResultEnum.ILLEGAL_ERROR);
        }
        if (!EnumUtils.isValidEnum(RequestType.class,appTypeStr)){
            throw new BaseException(ResultEnum.ILLEGAL_ERROR);
        }
    }


    private UserCacheHolder checkTokenAndGetUser(String appTypeStr, String tokenStr) {

            //先解密token
            String s = Aes.aesDecrypt(tokenStr);
           if(CheckEmptyUtil.isEmpty(s)){
               throw new BaseException(ResultEnum.ILLEGAL_ERROR);
            }

            String userName=s.split(":")[0];
            String key = appTypeStr + ":" + "token" + ":" + userName;
            boolean hasToken = RedisUtil.hasKey(key);
            if (!hasToken) {
                logger.error("key：{}，在redis中不存在", key);
                throw new BaseException(ResultEnum.TOKEN_INVALID_ERROR);
            }
            LoginUser loginUser = (LoginUser)RedisUtil.get(key);
            if (loginUser==null) {
                logger.error("loginUser信息在redis中为空");
                throw new BaseException(ResultEnum.TOKEN_INVALID_ERROR);
            }

            if(!loginUser.getToken().equals(tokenStr)){
                throw new BaseException(ResultEnum.TOKEN_INVALID_ERROR);
            }

            String userKey = Constant.LOGINUSER + ":" + loginUser.getUserId();
            boolean hasUserId = RedisUtil.hasKey(userKey);
            if (!hasUserId) {
                logger.error("userKey：{}，在redis中不存在", userKey);
                throw new BaseException(ResultEnum.TOKEN_INVALID_ERROR);
            }
            UserDO userDo = (UserDO) RedisUtil.get(userKey);
            if (userDo == null) {
                logger.error("userDo信息在redis中为空");
                throw new BaseException(ResultEnum.TOKEN_INVALID_ERROR);
            }
            //更新redis失效时间
            RedisUtil.expire(key, Constant.REDIS_EXPIRE);

            UserCacheHolder cacheHolder=new UserCacheHolder();
            cacheHolder.setLoginUser(loginUser);
            cacheHolder.setUserDo(userDo);

            return cacheHolder;

    }


    private void checkBusinessParams(UserDO userDo) {
        if(Objects.equals(userDo.getStatus(),0)){
            logger.error("用户账户被禁用");
            throw new BaseException(ResultEnum.USER_FORBIDDEN);
        }
    }


    @After("AuthPointCut()")
    public void methodAfter(JoinPoint joinPoint){
        LoginUserHolder.clearLoginUserHolder();
    }

}
